/*
	Copyright 2009 Benjamin Vedder	vedder87@gmail.com
	
	This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    */

package com.google.code.retrobox.editor.maps;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.List;

import javax.swing.*;

import com.google.code.retrobox.editor.commons.dialog.AddRowDialog;
import com.google.code.retrobox.editor.dataCollections.MapData;
import com.google.code.retrobox.editor.dataCollections.TileSet;
import com.google.code.retrobox.editor.tiles.Tile;
import com.google.code.retrobox.editor.tiles.TileSetPanel;


public class MapEditor extends JPanel implements ActionListener {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	// Parameters
	public static final char defaultTile = 0x80;
	
	// Stuff
	public TileSet tileset;
	public MapData map;

	public TileSetPanel setPanel;
	public TilePlane tilePlane;
	
	private JFrame parent;
	
	private AddRowDialog rowAddDialog;
	private RemoveRowDialog rowRemoveDialog;
	
	
	public static enum Pos {NORTH, SOUTH, EAST, WEST};

	// Components
	// Checkbox
	private JCheckBox gridBox;
	private JCheckBox collBox;
	
	// Buttons
	private JButton addRowsButton;
	private JButton removeRowsButton;

	private JPanel	editorPanel,
					controlPanel;

	public MapEditor(char[] set, char[] col, char[] mp, int w, int h, JFrame parent) {
		this.parent = parent;
		
		tileset = new TileSet(set, col);
		map = new MapData(tileset, mp, w, h);
		setPanel = new TileSetPanel(tileset);
		tilePlane = new TilePlane(map);
		
		init();
	}
	
	public MapEditor(MapData map, JFrame parent) {
		this.parent = parent;
		
		tileset = map.getTileSet();
		this.map = map;
		setPanel = new TileSetPanel(tileset);
		tilePlane = new TilePlane(map);
		
		init();
	}
	
	private void init() {
		setLayout(new BorderLayout());
		
		gridBox = new JCheckBox("Draw grid  ", true);
		collBox = new JCheckBox("Show collisions  ", false);
		addRowsButton = new JButton("Add rows...");
		removeRowsButton = new JButton("Remove rows...");
		
		gridBox.addActionListener(this);
		collBox.addActionListener(this);
		addRowsButton.addActionListener(this);
		removeRowsButton.addActionListener(this);
		
		editorPanel = new JPanel(new BorderLayout());
		controlPanel = new JPanel(new BorderLayout());

		map.setTileSetPanel(setPanel);
		Tile.setDrawGrid(gridBox.isSelected());
		Tile.setShowCollision(collBox.isSelected());
		

		JScrollPane mapScroll = new JScrollPane(tilePlane);
		editorPanel.add(mapScroll, BorderLayout.CENTER);
		controlPanel.add(setPanel, BorderLayout.EAST);
		
		JPanel toolPanel = new JPanel(new BorderLayout());
		JPanel actionPanel = new JPanel(new BorderLayout());
		JPanel buttonPanel = new JPanel(new GridLayout(2, 1));
		
		
		// ----------- Buttons -------------- //
		buttonPanel.add(addRowsButton);
		buttonPanel.add(removeRowsButton);
		
		actionPanel.add(buttonPanel, BorderLayout.NORTH);
		actionPanel.setBorder(BorderFactory.createEtchedBorder());
		
		toolPanel.add(actionPanel, BorderLayout.WEST);
		// ---------------------------------- //
		
		
		// ------------- Checkboxes ----------- //
		JPanel setPanel = new JPanel(new BorderLayout());
		JPanel boxPanel = new JPanel(new GridLayout(2, 1));
		
		boxPanel.add(gridBox);
		boxPanel.add(collBox);
		
		setPanel.add(boxPanel, BorderLayout.NORTH);
		setPanel.setBorder(BorderFactory.createEtchedBorder());
		
		toolPanel.add(setPanel, BorderLayout.EAST);
		// ------------------------------------- //
		
		
		// --------------- Map status ------------ //
		JLabel statusLabel = new JLabel();
		
		statusLabel.setText("<html>" +
				"<font size=4><font color=blue><b>Map stats</b></font size=3></font color=blue><BR>" +
				"Width: " + map.getMapWidth() + "<BR>" +
				"Height: " + map.getMapHeight() + "<BR>" +
				"Tiles: " + map.getMapWidth() * map.getMapHeight() + "<BR>" +
				"</html>");
		
		statusLabel.setBorder(BorderFactory.createEtchedBorder());
		toolPanel.add(statusLabel);
		// --------------------------------------- //
		
		
		controlPanel.add(toolPanel, BorderLayout.CENTER);
		
		controlPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Tools"));
		
		add(editorPanel, BorderLayout.CENTER);
		add(controlPanel, BorderLayout.SOUTH);
	}
	
	public void setTileset(TileSet ts) {
		tileset = ts;
		
		int w = map.getMapWidth();
		int h = map.getMapHeight();
		char [] mp = map.getDataRaw();
		
		map = new MapData(tileset, mp, w, h);
		setPanel = new TileSetPanel(tileset);
		tilePlane = new TilePlane(map);
		
		removeAll();
		
		init();
	}
	
	/**
	 * Add horizontal/vertical rows to the current map.
	 * @param rows
	 * The number of Horizontal/vertical rows to add.
	 * @param pos
	 * Where to add them (North, south, east, west).
	 */
	public void addRows(int rows, Pos pos) {
		List<Character> md = new LinkedList<Character>();
		
		int w = map.getMapWidth();
		int h = map.getMapHeight();
		char [] mp = map.getDataRaw();
		
		if (pos == Pos.NORTH) {
			for (int i = 0;i < rows * w;i++) {
				md.add(defaultTile);
			}
			for (int i = 0;i < mp.length;i++) {
				md.add(mp[i]);
			}
			h = h + rows;
		} else if (pos == Pos.SOUTH) {
			for (int i = 0;i < mp.length;i++) {
				md.add(mp[i]);
			}
			for (int i = 0;i < rows * w;i++) {
				md.add(defaultTile);
			}
			h = h + rows;
		} else if (pos == Pos.EAST) {
			for (int i = 0;i < h;i++) {
				for (int j = 0;j < w;j++) {
					md.add(mp[j + (w * i)]);
				}
				for (int j = 0;j < rows;j++) {
					md.add(defaultTile);
				}
			}
			w = w + rows;
		} else if (pos == Pos.WEST) {
			for (int i = 0;i < h;i++) {
				for (int j = 0;j < rows;j++) {
					md.add(defaultTile);
				}
				for (int j = 0;j < w;j++) {
					md.add(mp[j + (w * i)]);
				}
			}
			w = w + rows;
		}
		
		mp = new char[w * h];
		
		for (int i = 0;i < md.size();i++) {
			mp[i] = md.get(i);
		}
		
		map = new MapData(tileset, mp, w, h);
		setPanel = new TileSetPanel(tileset);
		tilePlane = new TilePlane(map);
		
		removeAll();
		
		init();
	}
	
	/**
	 * Remove horizontal/vertical rows from the current map.
	 * @param rows
	 * The number of Horizontal/vertical rows to remove.
	 * @param pos
	 * Where to remove them (North, south, east, west).
	 */
	public void removeRows(int rows, Pos pos) {
		List<Character> md = new LinkedList<Character>();

		int w = map.getMapWidth();
		int h = map.getMapHeight();
		char[] mp = map.getDataRaw();
		
		if (pos == Pos.NORTH) {
			for (int i = w * rows;i < w * h;i++) {
				md.add(mp[i]);
			}
			h = h - rows;
		} else if (pos == Pos.SOUTH) {
			for (int i = 0;i < ((w * h) - w * rows);i++) {
				md.add(mp[i]);
			}
			h = h - rows;
		} else if (pos == Pos.EAST) {
			for (int i = 0;i < h;i++) {
				for (int j = 0;j < w - rows;j++) {
					md.add(mp[j + (w * i)]);
				}
			}
			w = w - rows;
		} else if (pos == Pos.WEST) {
			for (int i = 0;i < h;i++) {
				for (int j = rows;j < w;j++) {
					md.add(mp[j + (w * i)]);
				}
			}
			w = w - rows;
		}
		
		mp = new char[w * h];
		
		for (int i = 0;i < md.size();i++) {
			mp[i] = md.get(i);
		}
		
		map = new MapData(tileset, mp, w, h);
		setPanel = new TileSetPanel(tileset);
		tilePlane = new TilePlane(map);
		
		removeAll();
		
		init();
	}

	public void actionPerformed(ActionEvent e) {

		if (e.getSource() == gridBox) {
			Tile.setDrawGrid(gridBox.isSelected());
			repaint();
		} else if (e.getSource() == collBox) {
			Tile.setShowCollision(collBox.isSelected());
			repaint();
		} else if (e.getSource() == addRowsButton) {
			rowAddDialog = new AddRowDialog(parent);
			rowAddDialog.addActionListener(this);
		} else if (e.getSource() == rowAddDialog) {
			addRows(rowAddDialog.gerRowNum(), rowAddDialog.getPos());
		} else if (e.getSource() == removeRowsButton) {
			rowRemoveDialog = new RemoveRowDialog(parent);
			rowRemoveDialog.addActionListener(this);
		} else if (e.getSource() == rowRemoveDialog) {
			removeRows(rowRemoveDialog.gerRowNum(), rowRemoveDialog.getPos());
		}

	}
}




